import sys
import folium
import io
import math
from PyQt5.QtWidgets import (QApplication, QMainWindow, QPushButton, QVBoxLayout, 
                            QWidget, QLabel, QTableWidget, QTableWidgetItem, QHBoxLayout)
from PyQt5.QtWebEngineWidgets import QWebEngineView
from PyQt5.QtCore import Qt, QObject, pyqtSlot, QUrl
from PyQt5.QtWebChannel import QWebChannel
from folium import plugins

class MapWindow(QMainWindow):
    def __init__(self):
        super().__init__()
        self.setWindowTitle('无人机地图标记系统')
        self.setGeometry(100, 100, 1000, 800)
        
        # 创建主窗口部件
        self.central_widget = QWidget()
        self.setCentralWidget(self.central_widget)
        self.layout = QVBoxLayout(self.central_widget)
        
        # 创建地图视图
        self.web_view = QWebEngineView()
        self.layout.addWidget(self.web_view)
        
        # 创建标签显示点击坐标
        self.coord_label = QLabel('点击地图添加标记（左键添加，右键删除最后一个标记）')
        self.layout.addWidget(self.coord_label)
        
        # 创建表格显示所有标记点
        self.table = QTableWidget()
        self.table.setColumnCount(3)
        self.table.setHorizontalHeaderLabels(['标记点', '经度', '纬度'])
        self.layout.addWidget(self.table)
        
        # 初始化地图（合肥市中心坐标）
        self.map = folium.Map(
            location=[31.8206, 117.2272],
            zoom_start=12,
            tiles='http://webrd02.is.autonavi.com/appmaptile?lang=zh_cn&size=1&scale=1&style=7&x={x}&y={y}&z={z}',
            attr='高德地图',
            control_scale=True,
            zoom_control=True
        )
        
        # 初始化标记点计数和列表
        self.marker_count = 0
        self.markers = []
        self.polyline = None
        
        # 创建点击事件处理
        page = self.web_view.page()
        page.setWebChannel(QWebChannel(page))
        
        class Bridge(QObject):
            def __init__(self, parent=None):
                super().__init__(parent)
                
            @pyqtSlot(float, float, str)
            def handleMapClick(self, lat, lng, button):
                if button == 'left':
                    self.parent().add_marker(lat, lng)
                elif button == 'right':
                    self.parent().remove_last_marker()
        
        self.bridge = Bridge(self)
        page.webChannel().registerObject("bridge", self.bridge)
        
        # 显示初始地图
        self.update_map()
        
    def update_table(self):
        """更新标记点表格"""
        self.table.setRowCount(len(self.markers))
        for i, marker in enumerate(self.markers):
            self.table.setItem(i, 0, QTableWidgetItem(f'点{i+1}'))
            self.table.setItem(i, 1, QTableWidgetItem(f'{marker["lng"]:.6f}'))
            self.table.setItem(i, 2, QTableWidgetItem(f'{marker["lat"]:.6f}'))
        
    def add_marker(self, lat, lng):
        """添加标记点"""
        self.marker_count += 1
        marker = folium.Marker(
            [lat, lng],
            popup=f'点{self.marker_count}\n经度: {lng:.6f}\n纬度: {lat:.6f}',
            icon=folium.Icon(color='red')
        ).add_to(self.map)
        
        # 保存标记点信息
        self.markers.append({
            "marker": marker,
            "lat": lat,
            "lng": lng
        })
        
        # 更新轨迹线和箭头
        if len(self.markers) > 1:
            # 获取所有点的坐标
            locations = [[m["lat"], m["lng"]] for m in self.markers]
            
            # 删除旧的轨迹线和箭头
            for layer in self.map._children.copy():
                if isinstance(self.map._children[layer], (folium.PolyLine, plugins.AntPath)):
                    del self.map._children[layer]
            
            # 添加新的轨迹线
            self.polyline = plugins.AntPath(
                locations=locations,
                weight=2,
                color='red',
                dash_array=[10, 20],  # 虚线样式
                delay=1000,  # 动画延迟
                pulse_color='red'  # 脉冲颜色
            ).add_to(self.map)
            
            # 在最后两个点之间的中点添加箭头
            last_point = locations[-1]
            prev_point = locations[-2]
            
            # 计算中点坐标
            mid_lat = (prev_point[0] + last_point[0]) / 2
            mid_lng = (prev_point[1] + last_point[1]) / 2
            
            # 计算方位角并调整箭头方向
            bearing = self._calculate_bearing(prev_point[0], prev_point[1], last_point[0], last_point[1])
            # 箭头需要旋转额外的90度来指向正确的方向
            arrow_rotation = bearing - 90
            
            # 添加箭头标记在中点位置
            folium.RegularPolygonMarker(
                location=[mid_lat, mid_lng],
                number_of_sides=3,
                radius=6,
                rotation=arrow_rotation,  # 使用调整后的旋转角度
                color='red',
                fill=True,
                fill_color='red'
            ).add_to(self.map)
        
        # 更新坐标显示
        self.coord_label.setText(f'点{self.marker_count} - 经度: {lng:.6f}, 纬度: {lat:.6f}')
        
        # 更新表格
        self.update_table()
        
        # 更新地图显示
        self.update_map()
        
    def remove_last_marker(self):
        """删除最后一个标记点"""
        if self.markers:
            # 删除最后一个标记点
            self.markers.pop()
            self.marker_count -= 1
            
            # 重新初始化地图
            self.map = folium.Map(
                location=[31.8206, 117.2272],
                zoom_start=12,
                tiles='http://webrd02.is.autonavi.com/appmaptile?lang=zh_cn&size=1&scale=1&style=7&x={x}&y={y}&z={z}',
                attr='高德地图',
                control_scale=True,
                zoom_control=True
            )
            
            # 重新添加所有标记点
            for i, marker_info in enumerate(self.markers):
                folium.Marker(
                    [marker_info["lat"], marker_info["lng"]],
                    popup=f'点{i+1}\n经度: {marker_info["lng"]:.6f}\n纬度: {marker_info["lat"]:.6f}',
                    icon=folium.Icon(color='red')
                ).add_to(self.map)
            
            # 如果还有多个点，重新添加轨迹线和箭头
            if len(self.markers) > 1:
                locations = [[m["lat"], m["lng"]] for m in self.markers]
                
                # 添加轨迹线
                self.polyline = plugins.AntPath(
                    locations=locations,
                    weight=2,
                    color='red',
                    dash_array=[10, 20],
                    delay=1000,
                    pulse_color='red'
                ).add_to(self.map)
                
                # 在最后两个点之间的中点添加箭头
                last_point = locations[-1]
                prev_point = locations[-2]
                
                # 计算中点坐标
                mid_lat = (prev_point[0] + last_point[0]) / 2
                mid_lng = (prev_point[1] + last_point[1]) / 2
                
                # 计算方位角并调整箭头方向
                bearing = self._calculate_bearing(prev_point[0], prev_point[1], last_point[0], last_point[1])
                arrow_rotation = bearing - 90
                
                # 添加箭头标记在中点位置
                folium.RegularPolygonMarker(
                    location=[mid_lat, mid_lng],
                    number_of_sides=3,
                    radius=6,
                    rotation=arrow_rotation,
                    color='red',
                    fill=True,
                    fill_color='red'
                ).add_to(self.map)
            
            # 更新表格
            self.update_table()
            
            # 更新地图显示
            self.update_map()
            
            if self.marker_count > 0:
                last_marker = self.markers[-1]
                self.coord_label.setText(f'点{self.marker_count} - 经度: {last_marker["lng"]:.6f}, 纬度: {last_marker["lat"]:.6f}')
            else:
                self.coord_label.setText('点击地图添加标记（左键添加，右键删除最后一个标记）')

    def update_map(self):
        """更新地图显示"""
        data = io.BytesIO()
        self.map.save(data, close_file=False)
        html_content = data.getvalue().decode()
        
        # 注入QWebChannel.js和必要的样式
        html_content = html_content.replace('</head>',
            """
            <script type="text/javascript" src="qrc:///qtwebchannel/qwebchannel.js"></script>
            <style>
            .folium-map {
                width: 100%;
                height: 100%;
                position: relative;
            }
            .leaflet-container {
                cursor: crosshair !important;
            }
            </style>
            <script>
            document.addEventListener('DOMContentLoaded', function() {
                var checkLeaflet = setInterval(function() {
                    var maps = Object.values(window).filter(function(value) {
                        return value && value._initHooksCalled && value.getContainer;
                    });
                    
                    if (maps.length > 0) {
                        clearInterval(checkLeaflet);
                        var map = maps[0];
                        
                        map.on('click', function(e) {
                            console.log('Map clicked:', e.latlng.lat, e.latlng.lng);
                            if (typeof QWebChannel !== 'undefined') {
                                new QWebChannel(qt.webChannelTransport, function(channel) {
                                    channel.objects.bridge.handleMapClick(e.latlng.lat, e.latlng.lng, 'left');
                                });
                            }
                        });
                        
                        map.on('contextmenu', function(e) {
                            if (typeof QWebChannel !== 'undefined') {
                                new QWebChannel(qt.webChannelTransport, function(channel) {
                                    channel.objects.bridge.handleMapClick(e.latlng.lat, e.latlng.lng, 'right');
                                });
                            }
                            return false;
                        });
                    }
                }, 100);
            });
            </script>
            </head>
            """
        )
        
        # 设置baseUrl以确保可以加载qwebchannel.js
        self.web_view.setHtml(html_content, baseUrl=QUrl("qrc:/"))
        
    def focus_on_drone(self, lat, lng):
        """聚焦到无人机位置"""
        self.map.location = [lat, lng]
        folium.Marker(
            [lat, lng],
            popup='无人机位置',
            icon=folium.Icon(color='blue')
        ).add_to(self.map)
        self.update_map()

    def _calculate_bearing(self, lat1, lon1, lat2, lon2):
        """计算两个点之间的方向角度"""
        dLon = lon2 - lon1
        dLat = lat2 - lat1
        y = math.sin(dLon) * math.cos(lat2)
        x = math.cos(lat1) * math.sin(lat2) - math.sin(lat1) * math.cos(lat2) * math.cos(dLon)
        bearing = math.atan2(y, x)
        bearing = (math.degrees(bearing) + 360) % 360
        return bearing

def main():
    app = QApplication(sys.argv)
    window = MapWindow()
    window.show()
    sys.exit(app.exec_())

if __name__ == '__main__':
    main() 